home *** CD-ROM | disk | FTP | other *** search
- {*************************************************************************}
- {* Copyright (c) Kim Kokkonen, TurboPower Software, 1986 *}
- {* Released to the public domain for personal, non-commercial use only *}
- {*************************************************************************}
- {.F-}
- {
- This program analyzes any set of files on any MSDOS disk drive to
- determine a measure of performance efficiency. The performance measure
- is based on how many sets of file sectors are not contiguous. When
- the sectors of a file are not contiguous, read and write times are
- longer since the drive heads are forced to seek to each non-contiguous
- sector.
-
- MSDOS Wildcards can be used to select any desired group of files in
- any drive or directory. A "Recursive" option allows you to look at
- all subdirectories of the start directory, and thus the entire disk
- if desired.
-
- Output includes a list of all files analyzed with various analytical
- information. Optionally, only those files with non-contiguous sectors
- can be listed. The output is written to STDOUT, so that it can be
- redirected or piped.
-
- A final summary section gives statistics for all of the files analyzed.
- This section is not redirectable.
-
- Examples:
-
- DISKCHK -?
- writes a help screen and halts.
-
- DISKCHK
- looks at all files in the current directory and writes to screen.
-
- DISKCHK C:\*.COM -R >BREAKS.DAT
- looks at all COM files on drive C: and writes those with breaks
- to the file BREAKS.DAT.
-
- DISKCHK A: | MORE
- pages all files in the root directory of drive A: through the
- DOS MORE filter.
-
- Written 1/21/86. Kim Kokkonen, TurboPower Software.
- 408-378-3672. Compuserve 72457,2131.
-
- Requires Turbo Pascal version 3 to compile.
- No known dependencies on the PCDOS version of Turbo.
- Compile with max heap = $A000 to allow maximum recursion
- area for subdirectory searching.
- }
- {.F+}
- {$P512}
- {$C-}
-
- PROGRAM DiskEfficiency(Output);
- {-measure the fraction of non-contiguous sectors in a group of files}
- CONST
- MaxFiles = 1024; {max number of files searched in a given directory}
- MaxDirs = 128; {maximum number of dirs in a given directory}
- OptionChar = '-'; {character which prefixes options on command line}
- version : string[4] = '1.00';
-
- TYPE
- DriveName = STRING[2];
- FileString = STRING[12];
- PathName = STRING[64];
- FileName = STRING[8];
- ExtName = STRING[3];
- LongString = STRING[255];
- FnameType = ARRAY[0..7] OF Char;
- FextType = ARRAY[0..2] OF Char;
- FATinRAM = ARRAY[0..32767] OF Byte;
-
- Darray =
- RECORD
- num : Integer;
- arr : ARRAY[1..MaxDirs] OF FileString;
- END;
-
- CompositeFilename =
- RECORD
- name : FileName;
- ext : ExtName;
- END;
-
- Farray =
- RECORD
- num : Integer;
- arr : ARRAY[1..MaxFiles] OF CompositeFilename;
- END;
-
- DTArec =
- RECORD
- DOSnext : ARRAY[1..21] OF Byte;
- attr : Byte;
- fTime, fDate, flSize, fhSize : Integer;
- FullName : ARRAY[1..13] OF Char;
- END;
-
- UnopenedFCBrec =
- RECORD
- flag : Byte;
- junk : ARRAY[0..4] OF Byte;
- SearchAttr : Byte;
- drive : Byte;
- fName : FnameType;
- fExt : FextType;
- attr : Byte;
- DOSnext : ARRAY[12..21] OF Byte;
- fTime, fDate, fCluster, flSize, fhSize : Integer;
- END;
-
- Registers =
- RECORD
- CASE Integer OF
- 1 : (ax, bx, cx, dx, bp, si, di, ds, es, flags : Integer);
- 2 : (al, ah, bl, bh, cl, ch, dl, dh : Byte);
- END;
-
- VAR
- reg : Registers;
- SavePath, StartPath : PathName;
- ConsoleOut, WroteFile, bigFAT, recursive, verbose : Boolean;
- dta : DTArec;
- tStart, tStop : Real;
- err : Text[128]; {non-redirectable status output written here}
- files : Farray;
- FATbytes, FATsectors, secSize, AvailableClusters, fBroken,
- TotalBreaks, ClustersUsed, fCount, alloUnits, secsPerAllo : Integer;
- FAT : ^FATinRAM;
-
- PROCEDURE error(errnum, erraddr : Integer);
- {-get back to home in case of a crash}
- BEGIN
- ChDir(SavePath);
- Halt(1);
- END;
-
- PROCEDURE Time(VAR sec : Real);
- {-return time of day in seconds since midnight}
- BEGIN
- reg.ah := $2C;
- MsDos(reg);
- sec := 1.0*(reg.dh+60.0*(reg.cl+60.0*reg.ch)+reg.dl/100.0);
- END; {time}
-
- PROCEDURE DoHalt(exitcode : Integer);
- {-halt}
- BEGIN
- ChDir(SavePath);
- Halt(exitcode);
- END; {dohalt}
-
- FUNCTION BreakPressed : Boolean;
- {-true if Break key has been pressed}
- {-note that keypressed function executes int 23 if ^C has been pressed}
- VAR
- c : Char;
- breakdown : Boolean;
- BEGIN
- {check current state}
- breakdown := False;
- WHILE KeyPressed AND NOT(breakdown) DO BEGIN
- Read(Kbd, c);
- IF c = ^C THEN breakdown := True;
- END;
- BreakPressed := breakdown;
- END; {breakpressed}
-
- PROCEDURE BreakHalt;
- {-executed when break is detected}
- {-exit with return code 1}
- BEGIN
- ChDir(SavePath);
- Halt(1);
- END; {breakhalt}
-
- PROCEDURE SetBreak;
- {-set the ctrl-break address to a process exit handler}
- BEGIN
- reg.ax := $2523;
- reg.ds := CSeg;
- reg.dx := Ofs(BreakHalt);
- MsDos(reg);
- END; {setbreak}
-
- FUNCTION IOstat(bit : Integer) : Boolean;
- {-check status of the standard I/O}
- {bit=0 for input, 1 for output}
- {returns true if I/O is through console}
- VAR
- temp0, temp1 : Boolean;
- BEGIN
- reg.ax := $4400;
- reg.bx := bit {standard input or output} ;
- MsDos(reg);
- temp0 := reg.dx AND 128 <> 0;
- temp1 := reg.dx AND (1 SHL bit) <> 0;
- iostat := temp0 AND temp1;
- END {iostat} ;
-
- PROCEDURE ParsePath(VAR start : PathName;
- VAR dName : DriveName;
- VAR pName : PathName;
- VAR fName : FileString);
- {-parse a full (perhaps incomplete) pathname into component parts}
- VAR
- i : Integer;
-
- FUNCTION FileExists(s : PathName; attr : Integer) : Boolean;
- {-determine whether a file exists with the specified attribute}
- BEGIN
- reg.ah := $4E;
- s[Succ(Length(s))] := #0;
- reg.ds := Seg(s);
- reg.dx := Ofs(s[1]);
- reg.cx := attr;
- MsDos(reg);
- FileExists := ((reg.flags AND 1) = 0) AND ((dta.attr AND 31) = attr);
- END; {fileexists}
-
- BEGIN
- {get drive name}
- i := Pos(':', start);
- IF i = 0 THEN BEGIN
- dName := '';
- pName := start;
- END ELSE BEGIN
- dName := Copy(start, 1, i);
- IF i = Length(start) THEN pName := '\'
- ELSE pName := Copy(start, Succ(i), 64);
- END;
-
- {see if wildcard specified}
- i := Pos('*', start)+Pos('?', start);
-
- {separate out filename and pathname}
- IF (i = 0) AND (FileExists(start, 16) OR (pName = '\')) THEN BEGIN
- {start specifies a subdirectory}
- fName := '*.*';
- IF pName <> '\' THEN pName := pName+'\';
- END ELSE BEGIN
- {parse out filename on end}
- i := Length(pName);
- WHILE (i > 0) AND NOT(pName[i] IN [':', '\', '/']) DO i := Pred(i);
- fName := Copy(pName, Succ(i), 63);
- pName := Copy(pName, 1, i);
- IF pName = '' THEN GetDir(0, pName);
- IF pName[Length(pName)] <> '\' THEN pName := pName+'\';
- END;
- END; {parsepath}
-
- FUNCTION Path(dName : DriveName; pName : PathName) : PathName;
- {-return legal pathname for chdir}
- VAR
- t : PathName;
- BEGIN
- t := dName;
- IF pName = '\' THEN
- t := t+pName
- ELSE
- t := t+Copy(pName, 1, Pred(Length(pName)));
- Path := t;
- END; {path}
-
- FUNCTION ReturnDriveNum(dName : DriveName) : Byte;
- {-return the drive number for an FCB call, 1=A, 2=B}
- CONST
- DriveLets : STRING[26] = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
- BEGIN
- IF dName = '' THEN
- ReturnDriveNum := 0
- ELSE
- ReturnDriveNum := Pos(UpCase(dName[1]), DriveLets);
- END; {returndrivenum}
-
- FUNCTION StUpcase(s : LongString) : LongString;
- {-return the uppercase of a string}
- VAR
- i : Byte;
- BEGIN
- FOR i := 1 TO Length(s) DO s[i] := UpCase(s[i]);
- StUpcase := s;
- END; {stupcase}
-
- PROCEDURE SetOptions;
- {-read command line and set up options and defaults}
- VAR
- i : Integer;
- c : Char;
- HaltSoon : Boolean;
- param : LongString;
-
- PROCEDURE WriteHelp;
- BEGIN
- WriteLn(err, 'Usage: DISKCHK [Options] [SearchPath] [>ResultFile]');
- WriteLn(err);
- WriteLn(err, ' DISKCHK measures the storage efficiency of any group of files on');
- WriteLn(err, ' any floppy or hard disk supported by MSDOS. It returns a list of');
- WriteLn(err, ' files with the number of clusters used, the number of non-contiguous');
- WriteLn(err, ' clusters and a measure of the efficiency of storage as it will affect');
- WriteLn(err, ' read/write performance. If all clusters are contiguous, the efficiency');
- WriteLn(err, ' is rated as 100%. Otherwise, the efficiency is downgraded by the');
- WriteLn(err, ' percentage of clusters that are non-contiguous.');
- WriteLn(err);
- WriteLn(err, ' If no options are specified, the files in the current drive and');
- WriteLn(err, ' directory are analyzed, and a report listing all non-contiguous');
- WriteLn(err, ' files found is written to the standard output.');
- WriteLn(err);
- WriteLn(err, 'Options:');
- WriteLn(err, ' SearchPath Start in the specified drive and directory, and search');
- writeln(err, ' those files matching any filespec given (wildcards ok).');
- writeln(err, ' If not specified, all files in current dir are analyzed.');
- WriteLn(err, ' -R search Recursively, down all subdirectories found.');
- WriteLn(err, ' -V Verbose mode. Write all files, including contiguous ones.');
- WriteLn(err, ' -A Automatic mode. Analyzes entire default drive.');
- WriteLn(err, ' -? write this Help message.');
- DoHalt(2);
- END; {writehelp}
-
- PROCEDURE DoError(message : LongString);
- {-display an error message}
- BEGIN
- WriteLn(err, message);
- HaltSoon := True;
- END; {doerror}
-
- BEGIN
- {get options}
- WriteLn(err);
- HaltSoon := False;
- i := 1;
- WHILE i <= ParamCount DO BEGIN
- {analyze options}
- param := ParamStr(i);
- IF param[1] = OptionChar THEN BEGIN
- {an option}
- IF Length(param) = 2 THEN BEGIN
- c := UpCase(param[2]);
- CASE c OF
- '?' : WriteHelp;
- 'R' : recursive := True;
- 'V' : verbose := true;
- 'A' : BEGIN
- recursive := True;
- StartPath := '\';
- END;
- END;
- END ELSE
- DoError('Unrecognized command option....'+ParamStr(i));
- END else
- {search path}
- StartPath := StUpcase(ParamStr(i));
- i := Succ(i);
- END;
- IF HaltSoon THEN BEGIN
- WriteLn(err, 'Type DISKCHK -? for help....');
- DoHalt(2);
- END;
- END; {setoptions}
-
- PROCEDURE SetDTA(VAR dta : DTArec);
- {-set new DTA address}
- BEGIN
- reg.ah := $1A;
- reg.ds := Seg(dta);
- reg.dx := Ofs(dta);
- MsDos(reg);
- END; {setdta}
-
- PROCEDURE ScanFiles(StartPath : PathName);
- {-get all files in pathnamed directory}
- {-called recursively in recursive mode}
- VAR
- dirs : Darray;
- dName : DriveName;
- pName, UsePath : PathName;
- fName : FileString;
- filNum : Integer;
- driveNum : Byte;
-
- PROCEDURE ParseDTA(VAR name, ext : FileString);
- {-return a name and extension from a DTA}
- VAR
- i : Byte;
- tempName : FileString;
- BEGIN
- i := 1;
- WHILE dta.FullName[i] <> #0 DO i := Succ(i);
- i := Pred(i);
- Move(dta.FullName, tempName[1], i);
- tempName[0] := Chr(i);
- i := Pos('.', tempName);
- IF i <= 1 THEN BEGIN
- name := tempName;
- ext := '';
- END ELSE BEGIN
- name := Copy(tempName, 1, Pred(i));
- ext := Copy(tempName, Succ(i), 3);
- END;
- END; {parsedta}
-
- FUNCTION GetFirst(attr : Integer; VAR StartPath : PathName;
- VAR name, ext : FileString;
- VAR rightdirattr : Boolean) : Boolean;
- {-return true and a name if first file is found}
- VAR
- foundone : Boolean;
- BEGIN
- reg.ah := $4E;
- reg.ds := Seg(StartPath);
- reg.dx := Ofs(StartPath[1]);
- reg.cx := attr;
- MsDos(reg);
- foundone := ((reg.flags AND 1) = 0);
- rightdirattr := (dta.attr AND 16) = (attr AND 16);
- IF foundone THEN
- {scan the DTA for the file name and extension}
- ParseDTA(name, ext);
- GetFirst := foundone;
- END; {getfirst}
-
- FUNCTION GetNext(attr : Integer; VAR name, ext : FileString;
- VAR rightdirattr : Boolean) : Boolean;
- {-return true and a name if another file is found}
- VAR
- foundone : Boolean;
- BEGIN
- reg.ah := $4F;
- reg.ds := Seg(dta);
- reg.dx := Ofs(dta);
- MsDos(reg);
- foundone := ((reg.flags AND 1) = 0);
- rightdirattr := (dta.attr AND 16) = (attr AND 16);
- IF foundone THEN
- {scan the DTA for the file name and extension}
- ParseDTA(name, ext);
- GetNext := foundone;
- END; {getnext}
-
- PROCEDURE GetFiles(attr : Integer;
- VAR files : Farray;
- VAR StartPath : PathName);
- {-return the files in the files array}
- VAR
- tempName, tempExt : FileString;
- rightdir : Boolean;
-
- BEGIN
- WITH files DO BEGIN
- StartPath[Succ(Length(StartPath))] := #0;
- num := 0;
- IF GetFirst(attr, StartPath, tempName, tempExt, rightdir) THEN
- REPEAT
- IF rightdir AND (tempName[1] <> '.') THEN BEGIN
- num := Succ(num);
- WITH arr[num] DO BEGIN
- name := tempName;
- ext := tempExt;
- END;
- END;
- UNTIL (num = MaxFiles) OR NOT(GetNext(attr, tempName, tempExt, rightdir));
- END;
- END; {getfiles}
-
- PROCEDURE GetDirs(attr : Integer;
- VAR dirs : Darray;
- VAR StartPath : PathName);
- {-return the directory names in the dirs array}
- VAR
- tempName, tempExt : FileString;
- rightdir : Boolean;
- BEGIN
- WITH dirs DO BEGIN
- StartPath[Succ(Length(StartPath))] := #0;
- num := 0;
- IF GetFirst(attr, StartPath, tempName, tempExt, rightdir) THEN
- REPEAT
- IF rightdir AND (tempName[1] <> '.') THEN BEGIN
- num := Succ(num);
- arr[num] := tempName;
- IF tempExt <> '' THEN arr[num] := arr[num]+'.'+tempExt;
- END;
- UNTIL (num = MaxDirs) OR NOT(GetNext(attr, tempName, tempExt, rightdir));
- END;
- END; {getdirs}
-
- PROCEDURE Analyze(driveNum : Byte; VAR fName : CompositeFilename);
- {-scan the file fname looking for the matchpattern}
- VAR
- FCB : UnopenedFCBrec;
- FCBreturn : UnopenedFCBrec ABSOLUTE dta;
- Breaks, LastCluster, Cluster : Integer;
- EndOfFile : Boolean;
- FATentry : Integer;
- FileClusters : Integer;
- Efficiency : Real;
-
- PROCEDURE InitFCB(VAR FCB : UnopenedFCBrec;
- driveNum : Byte;
- name : FileName;
- ext : ExtName);
- {-set up fcb for directory call}
- BEGIN
- FillChar(FCB, SizeOf(FCB), 32);
- WITH FCB DO BEGIN
- flag := $FF;
- SearchAttr := 7;
- drive := driveNum;
- Move(name[1], fName, Length(name));
- IF Length(ext) > 0 THEN
- Move(ext[1], fExt, Length(ext));
- END;
- END; {initfcb}
-
- FUNCTION GetFATentry(Cluster : Integer) : Integer;
- {-return the FAT entry for the specified cluster}
- VAR
- t : Integer;
- oddeven : Integer;
- BEGIN
- IF bigFAT THEN
- Move(FAT^[Cluster SHL 1], t, 2)
- ELSE BEGIN
- oddeven := 3*Cluster;
- Move(FAT^[oddeven SHR 1], t, 2);
- IF Odd(oddeven) THEN
- t := t SHR 4
- ELSE
- t := t AND $FFF;
- END;
- GetFATentry := t;
- END; {getfatentry}
-
- FUNCTION LastFATentry(FATentry : Integer) : Boolean;
- {-return true if the last FAT entry for the file}
- BEGIN
- IF bigFAT THEN
- LastFATentry := ((FATentry SHR 4) = $FFF) AND ((FATentry AND $F) >= 8)
- ELSE
- LastFATentry := (FATentry >= $FF8);
- END; {lastfatentry}
-
- FUNCTION FormattedName(dname:drivename;
- pname:pathname;
- name : FileName;
- ext : ExtName) : pathname;
- {-return a formatted name right padded with blanks}
- VAR
- t : pathname;
- BEGIN
- t := name;
- IF ext <> '' THEN
- t := t+'.'+ext;
- t:=dname+pname+t;
- WHILE Length(t) < 40 DO t := t+' ';
- FormattedName := t;
- END; {formattedname}
-
- BEGIN
-
- IF BreakPressed THEN BreakHalt;
-
- WITH fName DO BEGIN
-
- {fill in the FCB}
- InitFCB(FCB, driveNum, name, ext);
-
- {get detailed directory info from DOS}
- reg.ah := $11;
- reg.ds := Seg(FCB);
- reg.dx := Ofs(FCB);
- MsDos(reg);
- IF reg.al = $FF THEN BEGIN
- WriteLn(err, 'ERROR: file not found... ', name, '.', ext);
- DoHalt(1);
- END;
-
- {found the file, now trace its FAT}
- Cluster := FCBreturn.fCluster;
- LastCluster := Pred(Cluster);
- FileClusters := 1;
- Breaks := 0;
- REPEAT
- IF Cluster <> Succ(LastCluster) THEN
- Breaks := Succ(Breaks);
- FATentry := GetFATentry(Cluster);
- EndOfFile := LastFATentry(FATentry);
- IF NOT EndOfFile THEN BEGIN
- FileClusters := Succ(FileClusters);
- LastCluster := Cluster;
- Cluster := FATentry;
- END;
- UNTIL EndOfFile;
-
- {update counters}
- fCount := Succ(fCount);
- IF Breaks > 0 THEN BEGIN
- fBroken := Succ(fBroken);
- TotalBreaks := TotalBreaks+Breaks;
- END;
- ClustersUsed := ClustersUsed+FileClusters;
- IF FileClusters = 1 THEN
- Efficiency := 100.0
- ELSE
- Efficiency := 100.0*(1.0-Int(Breaks)/Int(FileClusters-1));
-
- IF verbose OR (Efficiency <> 100.0) THEN BEGIN
- WroteFile := True;
- {.F-}
- WriteLn(FormattedName(dname,pname,name,ext),' ',
- FCBreturn.fCluster:5,' ',
- FileClusters:5,' ',
- Breaks:5,' ',
- 1.0*secsize*FileClusters*secsPerAllo:7:0, ' ',
- efficiency:5:1
- );
- {.F+}
- END;
- END;
- END; {analyze}
-
- BEGIN
- {get a list of all normal, readonly, hidden matching files in startpath}
- ParsePath(StartPath, dName, pName, fName);
- UsePath := dName+pName+fName;
- GetFiles(7, files, UsePath);
-
- {move to the current directory to allow FCBs}
- ChDir(Path('', pName));
- driveNum := ReturnDriveNum(dName);
-
- {check each file}
- FOR filNum := 1 TO files.num DO Analyze(driveNum, files.arr[filNum]);
-
- {look at subdirectories}
- IF recursive THEN BEGIN
- {get all subdirectories}
- UsePath := dName+pName+'*.*';
- GetDirs(19, dirs, UsePath);
- {look in the subdirectories}
- FOR filNum := 1 TO dirs.num DO BEGIN
- {build a pathname to the subdirectory}
- UsePath := dName+pName+dirs.arr[filNum]+'\'+fName;
- {call recursively}
- ScanFiles(UsePath);
- END;
- END;
- END; {scanfiles}
-
- PROCEDURE InitializeGlobals;
- {-set up all global data structures}
- BEGIN
- {get default directory and disk}
- GetDir(0, StartPath);
- SavePath := StartPath;
- consoleout:=iostat(1);
- errorptr := Ofs(error);
- Assign(err, 'ERR:');
- Rewrite(err);
- SetBreak;
- SetDTA(dta);
- {set default flags and counters}
- recursive := False;
- verbose := false;
- fCount := 0;
- TotalBreaks := 0;
- ClustersUsed := 0;
- fBroken := 0;
- WroteFile := False;
- END; {initializeglobals}
-
- PROCEDURE GetDriveInfo;
- {-determine number of clusters, fat entry size, etc. for the specified drive}
- VAR
- dName : DriveName;
- pName : PathName;
- fName : FileString;
- driveNum : Byte;
- driveid : Byte;
- error : Integer;
- fatofs, sec : Integer;
-
- PROCEDURE getFAT(DOSnum : Byte; VAR driveid : Byte;
- VAR secSize, alloUnits, secsPerAllo : Integer);
- {-read the FAT ID info for the specified drive}
- BEGIN
- reg.ah := $1C;
- reg.dl := DOSnum;
- MsDos(reg);
- secSize := reg.cx;
- alloUnits := reg.dx;
- secsPerAllo := reg.al;
- driveid := Mem[reg.ds:reg.bx];
- END; {getfat}
-
- FUNCTION GetFreeSpace(driveNum : Byte) : Integer;
- {-return the number of free clusters on the drive}
- BEGIN
- reg.ah := $36;
- reg.dl := Succ(driveNum);
- MsDos(reg);
- GetFreeSpace := reg.bx;
- END; {GetFreeSpace}
-
- PROCEDURE DOSreadSectors(drive : Byte;
- LSN : Integer;
- sects : Integer;
- VAR buffer;
- VAR error : Integer);
- {-execute int 25 to read disk through DOS at low level}
- BEGIN
- INLINE(
- $1E/ {PUSH DS}
- $8A/$46/$10/ {MOV AL,[BP+10]}
- $8B/$56/$0E/ {MOV DX,[BP+0E]}
- $8B/$4E/$0C/ {MOV CX,[BP+0C]}
- $C5/$5E/$08/ {LDS BX,[BP+08]}
- $CD/$25/ {INT 25}
- $72/$02/ {JB 0113}
- $31/$C0/ {XOR AX,AX}
- $9D/ {POPF }
- $1F/ {POP DS}
- $5D/ {POP BP}
- $C4/$7E/$04/ {LES DI,[BP+04]}
- $26/ {ES: }
- $89/$05 {MOV [DI],AX}
- );
- END; {dosreadsectors}
-
- FUNCTION CurrentDrive : Byte;
- {-return the current drive number, 0=A, 1=B}
- BEGIN
- reg.ah := $19;
- MsDos(reg);
- CurrentDrive := reg.al;
- END; {currentdrive}
-
- BEGIN
- {break up the starting path}
- ParsePath(StartPath, dName, pName, fName);
-
- {change to the drive we're analyzing}
- IF dName <> '' THEN BEGIN
- ChDir(dName);
- driveNum := ReturnDriveNum(dName)-1; {0=A,1=B}
- END ELSE
- driveNum := CurrentDrive;
-
- {get FAT information}
- getFAT(0, driveid, secSize, alloUnits, secsPerAllo);
-
- {test whether 8 bit or 16 bit fat}
- bigFAT := (alloUnits < 0) OR (alloUnits > 4086);
-
- {allocate memory where we will keep the FAT}
- IF bigFAT THEN
- FATbytes := alloUnits SHL 1
- ELSE
- FATbytes := (3*alloUnits) SHR 1;
- IF FATbytes <= 0 THEN BEGIN
- WriteLn(err, 'Error in FAT size calculation');
- DoHalt(1);
- END;
- GetMem(FAT, FATbytes);
-
- FATsectors := FATbytes DIV secSize;
- IF (FATbytes AND Pred(secSize)) <> 0 THEN FATsectors := Succ(FATsectors);
- {read in the FAT}
- fatofs := 0;
- sec := 1;
- WHILE sec <= FATsectors DO BEGIN
- DOSreadSectors(driveNum, sec, 1, FAT^[fatofs], error);
- IF error <> 0 THEN BEGIN
- WriteLn(err, 'error reading FAT');
- DoHalt(1);
- END;
- sec := Succ(sec);
- fatofs := fatofs+512;
- END;
-
- {get number of available clusters}
- AvailableClusters := GetFreeSpace(driveNum);
-
- END; {getdriveinfo}
-
- PROCEDURE WriteResults;
- VAR
- Efficiency : Real;
- BEGIN
- IF ClustersUsed = 1 THEN
- Efficiency := 100.0
- ELSE
- Efficiency := 100.0*(1.0-TotalBreaks/(ClustersUsed-1.0));
- WriteLn(err);
- WriteLn(err, 'total files analyzed : ', fCount);
- WriteLn(err, 'total clusters used in these files : ', ClustersUsed);
- WriteLn(err, 'total files with cluster breaks : ', fBroken);
- WriteLn(err, 'total cluster breaks : ', TotalBreaks);
- WriteLn(err, 'total free clusters on disk : ', AvailableClusters);
- WriteLn(err, 'total clusters on disk : ', alloUnits);
- WriteLn(err, 'percent of disk free : ', (100.0*AvailableClusters/alloUnits):0:1, '%');
- WriteLn(err, 'total bytes on disk : ', (1.0*secSize*secsPerAllo*alloUnits):0:0);
- WriteLn(err, 'percent of clusters contiguous : ', Efficiency:0:1, '%');
- IF tStop-tStart <= 0 THEN Exit;
- WriteLn(err, 'file rate : ', (fCount/(tStop-tStart)):0:1, ' files/sec');
- END; {writeresults}
-
- BEGIN
- InitializeGlobals;
- SetOptions;
- WriteLn(err, 'Disk Performance Analyzer - by TurboPower Software - version ',version);
- GetDriveInfo;
- if consoleout then begin
- writeln(err);
- WriteLn(err,'Filename Start Clusters Breaks Bytes Effic');
- end;
- Time(tStart);
- ScanFiles(StartPath);
- Time(tStop);
- IF consoleout and not(WroteFile) THEN
- WriteLn(err,'--------------------- none --------------------------');
- WriteResults;
- ChDir(SavePath);
- END.
-